//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shp.Runtime.Sitka.ServiceAgent;
using Shp.Runtime.Contract;
using Shp.Runtime.DataModel.Sitka.Tests.Mocks;
using Shp.Runtime.Sitka.ServiceAgent.Managers;
using Shp.Runtime.DataModel.Sitka.Tests.Entities;

namespace Shp.Runtime.DataModel.Sitka.Tests
{
    [TestClass]
    public class BaseDataModelFixture
    {
        private const string EntityDefNameMock = "position";
        private static TenantEntity tenantMock;
        private static TenantEntity tenantListMock;
        private MetadataInitialize testMetadataInitializer;
        private TestableRepositoryFactory testRepositoryfactory;

        [TestInitialize]
        public void Initialize()
        {
            testMetadataInitializer = new MetadataInitialize();

            testRepositoryfactory = new TestableRepositoryFactory(testMetadataInitializer.TenantId);
            testRepositoryfactory.CreateContainers();

            testMetadataInitializer.Container = testRepositoryfactory.MetadataContainerName;
            testMetadataInitializer.CreateTenant();
            testMetadataInitializer.CreateTypes();
            testMetadataInitializer.CreateEntityDef();
            testMetadataInitializer.CreateEntityDefFields();
            testMetadataInitializer.CreateViewDef();
            testMetadataInitializer.CreateViewDefFields();
        }

        [TestCleanup]
        public void TestCleanUp()
        {
            testRepositoryfactory.DeleteContainers();
        }

        [TestMethod]
        public void ShouldGetTypeList()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            GuidStringPair[] typeList = metadataAccess.GetTypeList();
            Assert.IsNotNull(typeList);
            Assert.AreEqual(5, typeList.Length);
        }

        [TestMethod]
        public void ShouldGetEntityDefList()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            Dictionary<Guid, string> entityDefList = metadataAccess.GetEntityDefList();
            Assert.IsNotNull(entityDefList);
            Assert.AreEqual(1, entityDefList.Count);
        }

        [TestMethod]
        public void ShouldNotGetEntityDefFieldsForUnexistingEntity()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            EntityField[] fields = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "unexisting");
            Assert.IsNotNull(fields);
            Assert.AreEqual(0, fields.Length);
        }

        [TestMethod]
        public void ShouldGetEntityDefFields()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            EntityField[] fields = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "position");
            Assert.IsNotNull(fields);
            Assert.AreEqual(3, fields.Length);
        }

        [TestMethod]
        public void ShouldUpdateEntityDefFields()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);            
            EntityField[] fields = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "position");
            int oldFieldCount = fields.Length;

            List<EntityField> newFieldsStep1 = new List<EntityField>();
            newFieldsStep1.Add(MetadataInitialize.GetEntityFieldDef("field1"));
            newFieldsStep1.Add(MetadataInitialize.GetEntityFieldDef("field2"));
            newFieldsStep1.Add(MetadataInitialize.GetEntityFieldDef("field3"));
            
            newFieldsStep1.AddRange(fields);

            metadataAccess.UpdateEntityDef(testMetadataInitializer.TenantId, new Guid(MetadataInitialize.PositionEntityDefId), newFieldsStep1.ToArray());

            EntityField[] newFieldsState = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "position");

            Assert.IsNotNull(newFieldsState);
            Assert.AreEqual(oldFieldCount + 3, newFieldsState.Length);

            List<EntityField> newFieldsStep2 = new List<EntityField>();
            newFieldsStep2.Add(MetadataInitialize.GetEntityFieldDef("field1"));
            newFieldsStep2.Add(MetadataInitialize.GetEntityFieldDef("field4"));

            newFieldsStep1.AddRange(fields);

            metadataAccess.UpdateEntityDef(testMetadataInitializer.TenantId, new Guid(MetadataInitialize.PositionEntityDefId), newFieldsStep2.ToArray());

            newFieldsState = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "position");

            Assert.IsNotNull(newFieldsState);
            Assert.AreEqual(oldFieldCount + 2, newFieldsState.Length);
        }

        [TestMethod()]
        public void ShouldGetEntityDefFieldsByTenantId()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            EntityField[] fields = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "position");
            Assert.IsNotNull(fields);
            Assert.AreEqual(3, fields.Length);
        }

        [TestMethod()]
        public void ShouldUpdateViewDefFields()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            StringPair[] fields = metadataAccess.GetViewDefFields(testMetadataInitializer.TenantId, new Guid(MetadataInitialize.JobDetailViewId));
            int oldFields = fields.Length;

            List<StringPair> newFieldsStep1 = new List<StringPair>();
            newFieldsStep1.Add(new StringPair("Label1", "Name1"));
            newFieldsStep1.Add(new StringPair("Label2", "Name2"));
            newFieldsStep1.Add(new StringPair("Label3", "Name3"));

            newFieldsStep1.AddRange(fields);

            metadataAccess.UpdateViewDef(testMetadataInitializer.TenantId, new Guid(MetadataInitialize.JobDetailViewId), newFieldsStep1.ToArray());

            StringPair[] newFieldsState = metadataAccess.GetViewDefFields(testMetadataInitializer.TenantId, new Guid(MetadataInitialize.JobDetailViewId));

            Assert.IsNotNull(newFieldsState);
            Assert.AreEqual(oldFields + 3, newFieldsState.Length);

            List<StringPair> newFieldsStep2 = new List<StringPair>();
            newFieldsStep2.Add(new StringPair("Label1", "Name1"));
            newFieldsStep2.Add(new StringPair("Label4", "Name4"));

            newFieldsStep2.AddRange(fields);

            metadataAccess.UpdateViewDef(testMetadataInitializer.TenantId, new Guid(MetadataInitialize.JobDetailViewId), newFieldsStep2.ToArray());

            newFieldsState = metadataAccess.GetViewDefFields(testMetadataInitializer.TenantId, new Guid(MetadataInitialize.JobDetailViewId));

            Assert.IsNotNull(newFieldsState);
            Assert.AreEqual(oldFields + 2, newFieldsState.Length);            
        }

        [TestMethod()]
        public void ShouldGetViewDefList()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            Dictionary<Guid, string> viewDefList = metadataAccess.GetViewDefList();
            Assert.IsNotNull(viewDefList);
            Assert.AreEqual(2, viewDefList.Count);
        }

        [TestMethod()]
        public void ShouldGetViewDefFields()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            StringPair[] fields = metadataAccess.GetViewDefFields(testMetadataInitializer.TenantAlias, MetadataInitialize.JobSearchViewName);
            Assert.IsNotNull(fields);
            Assert.AreEqual(3, fields.Length);
        }

		[TestMethod()]
		public void ShouldAddInstance()
		{
			tenantMock = Mocks.MockHelper.GetTenant();
			ContainerManager.CreateContainer(tenantMock.Id.ToString());

            BaseDataModel dataModel = new BaseDataModel(testRepositoryfactory);

            Guid result = dataModel.AddInstance(tenantMock.Id, EntityDefNameMock, Mocks.MockHelper.GetMockEntityFields().ToArray());
			Assert.IsNotNull(result, "Guid Null");

			if (result == Guid.Empty)
			{
			    Assert.Fail("Guid Null");
			}
			ContainerManager.DeleteContainer(tenantMock.Id.ToString());
		}

		[TestMethod()]
		public void ShouldGetInstanceList()
		{
			tenantListMock = Mocks.MockHelper.GetTenant();
			ContainerManager.CreateContainer(tenantListMock.Id.ToString());
			
			StringPair[][] sitkaFields;

            BaseDataModel dataModel = new BaseDataModel(testRepositoryfactory);

			Guid instanceId = dataModel.AddInstance(tenantListMock.Id, EntityDefNameMock, Mocks.MockHelper.GetMockEntityFields().ToArray());

			List<Guid> listGuid = new List<Guid>();
			listGuid.Add(instanceId);

			sitkaFields = dataModel.GetInstanceList(tenantListMock.Id, EntityDefNameMock, listGuid.ToArray());

			Assert.IsNotNull(sitkaFields, "Give Null");
			
			if (sitkaFields.Length == 0)
			{
			    Assert.Fail("The returned List is empty...");
			}

			ContainerManager.DeleteContainer(tenantListMock.Id.ToString());
		}

        [TestMethod]
        public void ShouldGetIsVisibleFromAppFormField()
        {
            testMetadataInitializer.AddEntityDefField("MockFieldFalse", false);
            testMetadataInitializer.AddEntityDefField("MockFieldTrue", true);
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            EntityField[] fields = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "position");
            EntityField mockFieldFalse = fields.Single(field => field.Name == "MockFieldFalse");
            EntityField mockFieldTrue = fields.Single(field => field.Name == "MockFieldTrue");

            Assert.IsFalse(mockFieldFalse.IsVisibleFromApplicationForm);
            Assert.IsTrue(mockFieldTrue.IsVisibleFromApplicationForm);
        }

        [TestMethod]
        public void ShouldStoreIsVisibleFromAppFormField()
        {
            BaseDataModel metadataAccess = new BaseDataModel(testRepositoryfactory);
            testMetadataInitializer.AddEntityDefField("MockFieldFalse", false);
            EntityField[] fields = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "position");
            EntityField fieldCode = fields.Single(field => field.Name == "MockFieldFalse");

            Assert.IsFalse(fieldCode.IsVisibleFromApplicationForm);
            fieldCode.IsVisibleFromApplicationForm = true;

            metadataAccess.UpdateEntityDef(testMetadataInitializer.TenantId, new Guid(MetadataInitialize.PositionEntityDefId), fields);

           EntityField[] newFieldsState = metadataAccess.GetEntityDefFields(testMetadataInitializer.TenantAlias, "position");

           fieldCode = newFieldsState.Single(field => field.Name == "MockFieldFalse");

           Assert.IsTrue(fieldCode.IsVisibleFromApplicationForm);
        }
    }
}


